#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QDomDocument>
#include <QFile>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    m_pUI(new Ui::MainWindow)
{
    this->m_pUI->setupUi(this);
    this->m_pUI->WidgetAff1->setFocus();

    if(!this->loadScene("../Scene/scene1.xml"))
    {
        qDebug() << "Error loding the scene!";
        this->m_pScene = NULL;
        return;
    }

    this->m_pScene = new QGraphicsScene();
    QImage * output = new QImage(this->m_pTracer->m_pCamera->m_uWindow_width, this->m_pTracer->m_pCamera->m_uWindow_height, QImage::Format_RGB32);
    this->m_pScene->addItem(new QGraphicsPixmapItem(QPixmap::fromImage(*output)));
    delete output;
    this->m_pUI->graphicsView->setScene(this->m_pScene);

    this->m_pTimer = new QTimer(this);
    this->m_Start = 0;
    this->m_End = 0;
}

MainWindow::~MainWindow()
{
    delete this->m_pTracer;
    delete this->m_pUI;
}

void MainWindow::on_pushButton_clicked()
{
    this->m_pUI->label_2->setText("0.0 Sec");
    this->m_Start = clock ();
    this->m_pTimer->start(100);
    int MTC = this->m_pUI->spinBox_montecarlo->value();
    if(this->m_pTracer != 0)
    {
        QImage * output = new QImage(this->m_pTracer->m_pCamera->m_uWindow_width, this->m_pTracer->m_pCamera->m_uWindow_height, QImage::Format_RGB32);

        this->m_pTracer->run(output, this->m_pUI->spinBox->value()+1, MTC, this->m_pUI->progressBar);

        this->m_pScene->clear();
        this->m_pScene->addItem(new QGraphicsPixmapItem(QPixmap::fromImage(*output)));
        delete output;
    }
    this->m_pUI->progressBar->setValue(0);
    this->m_End = clock ();
    QString chronoStr;
    chronoStr.setNum((m_End - m_Start) / (double)CLOCKS_PER_SEC);
    this->m_pUI->label_2->setText(chronoStr + " Sec");
    m_pTimer->stop();
}

bool MainWindow::loadScene(QString filename)
{
    QFile file(filename);
    if (!file.open(QFile::ReadOnly | QFile::Text))
        return false;
    QDomDocument doc;
    if (!doc.setContent(&file, false))
    {
        file.close();
        return false;
    }
    file.close();
    QDomElement root = doc.documentElement();
    root = root.firstChildElement();


    if (this->m_pTracer)
        delete this->m_pTracer;
    this->m_pTracer = new CRaytracer();

    while(!root.isNull())
    {
        if(root.tagName() == "camera")
        {
            this->m_pTracer->m_pCamera = new CCamera();
            QDomElement Element = root.firstChildElement();
            while(!Element.isNull())
            {
                if(Element.tagName() == "resolution")
                {
                    QDomElement resElem = Element.firstChildElement();
                    while(!resElem.isNull())
                    {
                        if(resElem.tagName() == "width")
                            this->m_pTracer->m_pCamera->m_uWindow_width = resElem.text().toUInt() ;
                        else if(resElem.tagName() == "height")
                            this->m_pTracer->m_pCamera->m_uWindow_height = resElem.text().toUInt() ;
                        resElem = resElem.nextSiblingElement();
                    }
                }
                else if(Element.tagName() == "fovy")
                    this->m_pTracer->m_pCamera->m_fFovy = Element.text().toDouble();
                else if(Element.tagName() == "position")
                {
                    QDomElement posElem = Element.firstChildElement();
                    while (!posElem.isNull())
                    {
                        if (posElem.tagName() == "x")
                            this->m_pTracer->m_pCamera->m_Position.SetX(posElem.text().toDouble());
                        else if (posElem.tagName() == "y")
                            this->m_pTracer->m_pCamera->m_Position.SetY(posElem.text().toDouble());
                        else if (posElem.tagName() == "z")
                            this->m_pTracer->m_pCamera->m_Position.SetZ(posElem.text().toDouble());
                        posElem = posElem.nextSiblingElement();
                    }
                }
                else if(Element.tagName() == "direction")
                {
                    QDomElement dirElem = Element.firstChildElement();
                    while (!dirElem.isNull())
                    {
                        if (dirElem.tagName() == "x")
                            this->m_pTracer->m_pCamera->m_Direction.m_fX = dirElem.text().toDouble();
                        else if (dirElem.tagName() == "y")
                            this->m_pTracer->m_pCamera->m_Direction.m_fY = dirElem.text().toDouble();
                        else if (dirElem.tagName() == "z")
                            this->m_pTracer->m_pCamera->m_Direction.m_fZ = dirElem.text().toDouble();
                        dirElem = dirElem.nextSiblingElement();
                    }
                }
                else if(Element.tagName() == "up")
                {
                    QDomElement upElem = Element.firstChildElement();
                    while (!upElem.isNull())
                    {
                        if (upElem.tagName() == "x")
                            this->m_pTracer->m_pCamera->m_Up.m_fX = upElem.text().toDouble();
                        else if (upElem.tagName() == "y")
                            this->m_pTracer->m_pCamera->m_Up.m_fY = upElem.text().toDouble();
                        else if (upElem.tagName() == "z")
                            this->m_pTracer->m_pCamera->m_Up.m_fZ = upElem.text().toDouble();
                        upElem = upElem.nextSiblingElement();
                    }
                }
                else if(Element.tagName() == "side")
                {
                    QDomElement sideElem = Element.firstChildElement();
                    while (!sideElem.isNull())
                    {
                        if (sideElem.tagName() == "x")
                            this->m_pTracer->m_pCamera->m_Side.m_fX = sideElem.text().toDouble();
                        else if (sideElem.tagName() == "y")
                            this->m_pTracer->m_pCamera->m_Side.m_fY = sideElem.text().toDouble();
                        else if (sideElem.tagName() == "z")
                            this->m_pTracer->m_pCamera->m_Side.m_fZ = sideElem.text().toDouble();
                        sideElem = sideElem.nextSiblingElement();
                    }
                }
                else if(Element.tagName() == "sensitivity")
                    this->m_pTracer->m_pCamera->m_fSensitivity = Element.text().toDouble();
                else if(Element.tagName() == "speed")
                    this->m_pTracer->m_pCamera->m_fSpeed = Element.text().toDouble();

                Element = Element.nextSiblingElement();
            }
            if (this->m_pUI->WidgetAff1->m_pCamera != NULL)
                delete this->m_pUI->WidgetAff1->m_pCamera;
            this->m_pUI->WidgetAff1->m_pCamera = this->m_pTracer->m_pCamera;

        }
        else if(root.tagName() == "objects")
        {

            QDomElement Element = root.firstChildElement();
            while(!Element.isNull())
            {
                if (Element.tagName() == "sphere")
                {
                    CSphere * pSphere = new CSphere();
                    QDomElement sphElem = Element.firstChildElement();
                    while (!sphElem.isNull())
                    {
                        if (sphElem.tagName() == "position")
                        {
                            QDomElement posElem = sphElem.firstChildElement();
                            while (!posElem.isNull())
                            {
                                if (posElem.tagName() == "x")
                                    pSphere->m_Position.SetX(posElem.text().toDouble());
                                else if (posElem.tagName() == "y")
                                    pSphere->m_Position.SetY(posElem.text().toDouble());
                                else if (posElem.tagName() == "z")
                                    pSphere->m_Position.SetZ(posElem.text().toDouble());
                                posElem = posElem.nextSiblingElement();
                            }
                        }
                        else if (sphElem.tagName() == "radius")
                            pSphere->m_fRadius = sphElem.text().toDouble();
                        else if (sphElem.tagName() == "material")
                            pSphere->m_Material.loadMaterial(sphElem.text());
                        sphElem = sphElem.nextSiblingElement();
                    }
                    this->m_pTracer->add_objects(pSphere);
                    this->m_pUI->WidgetAff1->add_object(pSphere);
                }
                else if (Element.tagName() == "mesh")
                {
                    CMesh* pMesh = new CMesh();
                    QDomElement meshElem = Element.firstChildElement();
                    while(!meshElem.isNull())
                    {
                        if (meshElem.tagName() == "objfilepath")
                        {
                            pMesh->LoadOBJ(meshElem.text().toStdString());
                        }
                        else if (meshElem.tagName() == "material")
                        {
                            pMesh->m_Material.loadMaterial(meshElem.text());
                        }
                        meshElem = meshElem.nextSiblingElement();
                    }
                    this->m_pTracer->add_objects(pMesh);
                    this->m_pUI->WidgetAff1->add_object(pMesh);
                }
                Element = Element.nextSiblingElement();
            }
        }
        else if(root.tagName() == "lights")
        {
            QDomElement Element = root.firstChildElement();
            while(!Element.isNull())
            {
                if (Element.tagName() == "point_light")
                {
                    CLight* pLight = new CLight();
                    QDomElement plElem = Element.firstChildElement();
                    while(!plElem.isNull())
                    {
                        if (plElem.tagName() == "position")
                        {
                            QDomElement posElem = plElem.firstChildElement();
                            while(!posElem.isNull())
                            {
                                if (posElem.tagName() == "x")
                                    pLight->m_Position.SetX(posElem.text().toDouble());
                                else if (posElem.tagName() == "y")
                                    pLight->m_Position.SetY(posElem.text().toDouble());
                                else if (posElem.tagName() == "z")
                                    pLight->m_Position.SetZ(posElem.text().toDouble());
                                posElem = posElem.nextSiblingElement();
                            }
                        }
                        else if (plElem.tagName() == "color")
                        {
                            QDomElement clrElem = plElem.firstChildElement();
                            while(!clrElem.isNull())
                            {
                                if (clrElem.tagName() == "r")
                                    pLight->m_fRed = clrElem.text().toDouble();
                                else if (clrElem.tagName() == "g")
                                    pLight->m_fGreen = clrElem.text().toDouble();
                                else if (clrElem.tagName() == "b")
                                    pLight->m_fBlue = clrElem.text().toDouble();
                                clrElem = clrElem.nextSiblingElement();
                            }
                        }
                        plElem = plElem.nextSiblingElement();
                    }
                    this->m_pTracer->add_ligth(pLight);
                    this->m_pUI->WidgetAff1->add_object(pLight);
                }
                Element = Element.nextSiblingElement();
            }
        }
        root = root.nextSiblingElement();
    }
    if (!this->m_pTracer->m_pEnvironmentMaterial)
        this->m_pTracer->set_EnvironmentMaterial(CMaterial::getvoidContext());
    return true;
}

